/*
--------------------------------------------------------------------------------
				Ak-Lib. 
			 Project       	: Ak-Lib
			 Group         	: Ak-Lib R&D Team
			 Author        	: Ocean.Wang
			 Create Date 	: 05-01-2010
--------------------------------------------------------------------------------
Code Name 	:  A.K 	~v~
Description	:  Yet Another Cross-Platform Lib.
Cautions    	:
--------------------------------------------------------------------------------
Change History:
Version		: 0.1
Building 		: 05/01/10
10-05.01 first draft, build, debug and test.
--------------------------------------------------------------------------------
*/

#include "ak_socket.h"


/* Operation:
 IO Completion	: Operate is complete.
 Event Poll Select  : Operate is permit. (Edge Trigger / Level Trigger)
 Overlapped IO	: Operate is return imme, use the Event Trigger/Completion Routine to Inform User of Accomplish.
 
 SockFD will then call the EvHandle to Inform the Socket Layer Que to Process.
 IOCP	:
	read	-- 
		1. Call ReadFunc.
		2. Data is stored in buf that eUser pushed in netBufQ.
		3. GetCompletionStatus.
		4. Call EvHandle 4 User to Proc it.
	write	--
		1. Call WriteFunc.
		2. Data has been Tx.
		3. GetCompletionStatus.
		4. Call EvHandle 4 User to SYS_FREE the Buf stored in netBufQ.

 ESelect	:
	read	-- 
		1. Data has come to the socket.
		2. EnumEvents
		3. Call EvHandle 4 User to Rx it.
		4. Call ReadFunc. 
		
	write	-- 
		1. Socket is connected, ready for write. 
		2. EnumEvents
		3. Call EvHandle 4 Info User of that.
		4. Call WriteFunc.

 Overlap	:
	read	-- 
		1. Call ReadFunc.
		2. Data is stored in buf that eUser pushed in netBufQ.
		3. Event Trigger/CompRoutine to Inform Accomplish.
		4. Call EvHandle 4 User to Proc it.
		
	write	-- 
		1. Call WriteFunc.
		2. Data has been Tx.
		3. Event Trigger/CompRoutine to Inform eUser to SYS_FREE it.
		4. Call EvHandle 4 User to SYS_FREE the Buf stored in netBufQ.

ESelect + Overlap	:


The shutdown function does not close the socket. 
Any resources attached to the socket will not be freed until closesocket is invoked.
To assure that all data is sent and received on a connected socket before it is closed, 
an application should use shutdown to close connection before calling closesocket. 
For example, to initiate a graceful disconnect:

Call WSAAsyncSelect to register for FD_CLOSE notification. 
Call shutdown with how=SD_SEND. 
When FD_CLOSE received, call recv until zero returned, or SOCKET_ERROR. 
Call closesocket. 

Note:  The shutdown function does not block regardless of the SO_LINGER setting on the socket. :)!

*/


static 	int 	_gTraceLvl_Sock = TRACELVL_WARNING;

int 	SSock_SetTraceLvl(int lvl)
{
	int 	ret = -1;
	
	switch(lvl){
		case TRACELVL_FATAL:
		case TRACELVL_ERROR:
		case TRACELVL_WARNING:
		case TRACELVL_NORMAL:
		case TRACELVL_DEBUG:
		case TRACELVL_ALL:
			_gTraceLvl_Sock = lvl;
			ret = 0;
			break;
		default:
			break;
	}

	return ret;
}

int 	SSock_GetTraceLvl(void)
{
	return  _gTraceLvl_Sock;
}

static __inline sInt32 	SockConnTime_Tcp(S_SOCKET  sockFD, sInt32 *	seconds)
{
	sInt32 ret;
	sInt32 bytes = sizeof(uInt32);

	ret = getsockopt( sockFD, SOL_SOCKET, SO_CONNECT_TIME,(char *)seconds, &bytes );
	if(ret != 0){
		SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, "SO_CONNECT_TIME!\n");
		return _E_FAIL;
	}
	return _E_SUCC;
}


/* ------------------------------------------------------------------
** Error Handle : TCP / UDP Socket Operations 
*/
/*
Closing a socket with closesocket also cancels the association and selection of network events specified in :
WSAEventSelect for the socket. 
The application, however, still must call WSACloseEvent to explicitly close the event object and SYS_FREE any resources.
*/
static 	sInt32 	SErrHdl_Close(_t_sockEvUser * pEvUser, sInt32 errCode)
{
	S_SOCKET 		sockFd;
	_t_sockEvCb	 *	pCb;

	if((pEvUser) && ((sockFd = pEvUser->fd) != S_SOCKET_INVALID)){
		switch(errCode){
			case WSAENETDOWN:
			case WSAECONNRESET:
			case WSAECONNABORTED:
				/* How about the fdLink Change when the OP is processing? */
				/* Which will lead to WSA_OPERATION_ABORTED */
				closesocket(sockFd);

				/* LinkState & FdState */
				pEvUser->fd 	= S_SOCKET_INVALID;
				pCb = pEvUser->pCb;
				if(pCb && (pCb->cbErr)){
					return pCb->cbErr(pEvUser, errCode);
				}
				return _E_SUCC;
				break;

			default:
				return _E_SUCC;
				break;
		}
	}

	return _E_FAIL;
}

static 	sInt32 	SErrHdl_RouteChg(_t_sockEvUser * pEvUser, sInt32 errCode)
{
	S_SOCKET 		sockFd;
	_t_sockEvCb	 *	pCb;

	if((pEvUser) && ((sockFd = pEvUser->fd) != S_SOCKET_INVALID)){
		switch(errCode){
			case WSAENETUNREACH:
				return _E_SUCC;
				break;
			
			case WSAENETDOWN:
				/* How about the fdLink Change when the OP is processing? */
				/* Which will lead to WSA_OPERATION_ABORTED */
				closesocket(sockFd);

				/* LinkState & FdState */
				pEvUser->fd 	= S_SOCKET_INVALID;
				pCb = pEvUser->pCb;
				if(pCb && (pCb->cbErr)){
					return pCb->cbErr(pEvUser, errCode);
				}
				return _E_SUCC;
				break;

			default:
				return _E_SUCC;
				break;

		}
	}

	return _E_FAIL;
}

static 	sInt32 	SErrHdl_Default(_t_sockEvUser * pEvUser, sInt32 errCode)
{
	S_SOCKET 		sockFd;
	_t_sockEvCb	 *	pCb;	
	if(	(pEvUser) && ((sockFd = pEvUser->fd) != S_SOCKET_INVALID) &&
		(errCode == WSAENETDOWN)){
		/* How about the fdLink Change when the OP is processing? */
		closesocket(sockFd);

		/* LinkState & FdState */
		pEvUser->fd 	= S_SOCKET_INVALID;
		pCb = pEvUser->pCb;
		if(pCb && (pCb->cbErr)){
			return pCb->cbErr(pEvUser, errCode);
		}
		return _E_SUCC;
	}
	return _E_FAIL;
}


static 	sInt32 	SErrHdl_TCP_Disconn(_t_sockEvUser * pEvUser, sInt32 	errCode)
{
	S_SOCKET  	sockFd;
	_t_sockEvCb	 *	pCb;	

	if((pEvUser) && ((sockFd = pEvUser->fd) != S_SOCKET_INVALID)){
		switch(errCode){
			case S_SOCKET_ERROR:
				SYS_TRACE(_gTraceLvl_Sock, TRACELVL_WARNING, 
					"Sock[%-8d][0x%08x] - [%d]\n",	sockFd, pEvUser, errCode);
				break;

			default:
				/* How about the fdLink Change when the OP is processing? */
				SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, 
					"Sock[%-8d][0x%08x] - [%d]\n", 	sockFd, pEvUser, errCode);

				/* Which will lead to WSA_OPERATION_ABORTED */
				closesocket(sockFd);

				/* LinkState & FdState */
				pEvUser->fd 	= S_SOCKET_INVALID;
				pCb = pEvUser->pCb;
				if(pCb && (pCb->cbErr)){
					return pCb->cbErr(pEvUser, errCode);
				}
				break;
		}
		return _E_SUCC;
	}

	return _E_FAIL;
}


static 	sInt32 	SErrHdl_TCP_Connect(_t_sockEvUser * pEvUser, sInt32 	errCode)
{
	S_SOCKET  	sockFd;
	_t_sockEvCb	*	pCb;
	if((pEvUser) && ((sockFd = pEvUser->fd) != S_SOCKET_INVALID)){
		switch(errCode){
			case S_SOCKET_ERROR:
			case WSAEALREADY:
			case WSAEISCONN:
				SYS_TRACE(_gTraceLvl_Sock, TRACELVL_WARNING, 
					"Sock[%-8d][0x%08x] - [%d]\n", sockFd, pEvUser, errCode);
				break;

			case WSAECONNREFUSED:
			case WSAENETUNREACH:
			case WSAEHOSTUNREACH:
			case WSAETIMEDOUT:			
			case WSAEINVAL:
			case WSAENOBUFS:	
			case WSAEADDRINUSE:
			case WSAEADDRNOTAVAIL:
			case WSAEAFNOSUPPORT:
			case WSAENETDOWN:
				/* How about the fdLink Change when the OP is processing? */
				SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, 
					"Sock[%-8d][0x%08x] - [%d]\n", 
					sockFd, pEvUser, errCode);

				/* Which will lead to WSA_OPERATION_ABORTED */
				closesocket(sockFd);

				/* LinkState & FdState */
				pEvUser->fd 	= S_SOCKET_INVALID;
				pCb = pEvUser->pCb;
				if(pCb && (pCb->cbErr)){
					return pCb->cbErr(pEvUser, errCode);
				}
				break;

			default:
				SYS_TRACE(_gTraceLvl_Sock, TRACELVL_WARNING, 
					"Sock[%-8d][0x%08x] - [%d]\n", 	sockFd, pEvUser, errCode);
				break;
		}
		
		return _E_SUCC;
	}
	return _E_FAIL;
}

static 	sInt32 	SErrHdl_TCP_Accept(_t_sockEvUser * pEvUser, sInt32 	errCode)
{
	S_SOCKET  	sockFd;
	_t_sockEvCb *	pCb;

	if((pEvUser) && ((sockFd = pEvUser->fd) != S_SOCKET_INVALID)){
		switch(errCode){
			case S_SOCKET_ERROR:
			case WSAENOBUFS:
			case WSAENOTCONN:
			case WSAESHUTDOWN:
			case WSAEWOULDBLOCK:	
			case WSAEINVAL:
			case WSA_OPERATION_ABORTED: 	/* Cancel IO */
				SYS_TRACE(_gTraceLvl_Sock, TRACELVL_WARNING, 
					"Sock[%-8d][0x%08x] - [%d]\n",	sockFd, pEvUser, errCode);
				break;

			case WSAENETRESET:				/* Keep Alive? */
			case WSAENETDOWN:
			case WSAECONNRESET:
			case WSAECONNABORTED:			/* Terminated or Timeout ? */
				/* How about the fdLink Change when the OP is processing? */
				SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, 
					"Sock[%-8d][0x%08x] - [%d]\n", 	sockFd, pEvUser, errCode);

				/* Which will lead to WSA_OPERATION_ABORTED */
				closesocket(sockFd);

				/* LinkState & FdState */
				pEvUser->fd 	= S_SOCKET_INVALID;
				pCb = pEvUser->pCb;
				if(pCb && (pCb->cbErr)){
					return pCb->cbErr(pEvUser, errCode);
				}
				break;

			default:
				SYS_TRACE(_gTraceLvl_Sock, TRACELVL_WARNING, 
					"Sock[%-8d][0x%08x] - [%d]\n", 	sockFd, pEvUser, errCode);
				break;
		}

		return _E_SUCC;
	}

	return _E_FAIL;
}

static 	sInt32 	SErrHdl_TCP(_t_sockEvUser * pEvUser, sInt32 	errCode)
{
	S_SOCKET  	sockFd;
	_t_sockEvCb  *	pCb;

	if((pEvUser) && ((sockFd = pEvUser->fd) != S_SOCKET_INVALID)){
		switch(errCode){
			case S_SOCKET_ERROR:
			case WSAENOBUFS:
			case WSAENOTCONN:
			case WSAESHUTDOWN:
			case WSAEWOULDBLOCK:	
			case WSAEINVAL:
			case WSA_OPERATION_ABORTED: 	/* Cancel IO */
				SYS_TRACE(_gTraceLvl_Sock, TRACELVL_WARNING, 
					"Sock[%-8d][0x%08x] - [%d]\n", 	sockFd, pEvUser, errCode);
				break;

			case WSAENETRESET:				/* Keep Alive? */
			case WSAENETDOWN:
			case WSAECONNRESET:
			case WSAECONNABORTED:			/* Terminated or Timeout ? */
				/* How about the fdLink Change when the OP is processing? */
				SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, 
					"Sock[%-8d][0x%08x] - [%d]\n", 	sockFd, pEvUser, errCode);

				/* Which will lead to WSA_OPERATION_ABORTED */
				closesocket(sockFd);

				/* LinkState & FdState */
				pEvUser->fd 	= S_SOCKET_INVALID;
				pCb = pEvUser->pCb;
				if(pCb && (pCb->cbErr)){
					return pCb->cbErr(pEvUser, errCode);
				}
				break;

			default:
				SYS_TRACE(_gTraceLvl_Sock, TRACELVL_WARNING, 
					"Sock[%-8d][0x%08x] - [%d]\n", 	sockFd, pEvUser, errCode);
				break;
		}

		return _E_SUCC;
	}

	return _E_FAIL;
}

static 	sInt32 	SErrHdl_UDP(_t_sockEvUser * pEvUser, sInt32 	errCode)
{
	S_SOCKET  	sockFd;
	_t_sockEvCb	 *	pCb;

	if((pEvUser) && ((sockFd = pEvUser->fd) != S_SOCKET_INVALID)){
		switch(errCode){
			case S_SOCKET_ERROR:
			case WSAENOBUFS:
			case WSAENOTCONN:
			case WSAESHUTDOWN:
			case WSAEWOULDBLOCK:	
			case WSAEINVAL:
			case WSA_OPERATION_ABORTED: 	/* Cancel IO */
				SYS_TRACE(_gTraceLvl_Sock, TRACELVL_WARNING, 
					"Sock[%-8d][0x%08x] - [%d]\n", 	sockFd, pEvUser, errCode);
				break;

			case WSAECONNRESET:
			case WSAECONNABORTED:			/* Terminated or Timeout ? */
				SYS_TRACE(_gTraceLvl_Sock, TRACELVL_WARNING, 
					"Sock[%-8d][0x%08x] - [%d]\n", 	sockFd, pEvUser, errCode);
				break;
				
			case WSAENETRESET:				/* Keep Alive? */
			case WSAENETDOWN:
				/* How about the fdLink Change when the OP is processing? */
				SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, 
					"Sock[%-8d][0x%08x] - [%d]\n", 	sockFd, pEvUser, errCode);
				
				/* Which will lead to WSA_OPERATION_ABORTED */
				closesocket(sockFd);

				/* LinkState & FdState */
				pEvUser->fd 	= S_SOCKET_INVALID;
				pCb = pEvUser->pCb;
				if(pCb && (pCb->cbErr)){
					return pCb->cbErr(pEvUser, errCode);
				}
				break;

			default:
				SYS_TRACE(_gTraceLvl_Sock, TRACELVL_WARNING, 
					"Sock[%-8d][0x%08x] - [%d]\n", 	sockFd, pEvUser, errCode);
				break;
		}

		return _E_SUCC;
	}

	return _E_FAIL;
}


/* 
===========================================================
IO Async Funcs:
For WSAEventSelect.

Be Careful that the pAioClue Must be a Valid Global Context.
Here Acts as EPoll Mode. 
System will signal the Event of Permit to Read/Write/Accept/Connect/Close
===========================================================
*/
static 	sInt32 	SockTx_Tcp(_t_sockEvUser* 	pEvUser, _t_sgbuf * pSgBuf, long sgCnt)
{
	long 			flag, len;
	int 			ret, errCode;
	S_SOCKET		sockFd;
	_t_sockEvCb *	pCb;

	ret 	= _E_FAIL;
	errCode = S_SOCKET_ERROR;

	if(	(pEvUser)  && ((sockFd =pEvUser->fd) != S_SOCKET_INVALID) && 
		(pSgBuf) && (sgCnt > 0) ){
		flag = 0;
		errCode = WSASend(sockFd, 
						(LPWSABUF)(pSgBuf), sgCnt,	
						&len, flag, 
						NULL, NULL);	

		/* Check Ret */
		if(errCode == 0){
			SYS_TRACE(_gTraceLvl_Sock, TRACELVL_DEBUG, 
				"Sock[%-8d][0x%08x] Length:%ld\n", sockFd, pEvUser, len);
			ret = _E_SUCC;
		}
		else if((errCode == S_SOCKET_ERROR) && 
				((errCode = WSAGetLastError()) == WSAEWOULDBLOCK)){
			ret = _E_SUCC;
		}
		
		if(ret != _E_SUCC){
			/* Fail Check */
			SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, 
				"Sock[%-8d][0x%08x] Error\n", sockFd, pEvUser);

			pCb = pEvUser->pCb;
			if(pCb && (pCb->cbErr)){
				return pCb->cbErr(pEvUser, errCode);
			}
		}
	}
	
	return ret;
}


static 	sInt32 	SockTx_Udp(_t_sockEvUser * pEvUser, _t_sgbuf * pSgBuf, long sgCnt, S_SOCKET_ADDRIN * peer)
{
	long 			flag, len;
	int 			ret, errCode, sLen;
	S_SOCKET		sockFd;
	_t_sockEvCb *	pCb;
	
	ret 	= _E_FAIL;
	errCode = S_SOCKET_ERROR;

	if(	(pEvUser)  && ((sockFd =pEvUser->fd) != S_SOCKET_INVALID) && 
		(pSgBuf) && (sgCnt > 0) && peer ){
		/* OP */
		flag = 0; sLen = (sInt32)sizeof(S_SOCKET_ADDRIN);
		errCode = WSASendTo(sockFd, 
							(LPWSABUF)(pSgBuf), sgCnt,
							&len, flag,
							(S_SOCKET_ADDR *)peer, sLen,
							NULL, NULL);	
		
		/* Check Ret */
		if(errCode == 0){
			SYS_TRACE(_gTraceLvl_Sock, TRACELVL_DEBUG, 
				"Sock[%-8d][0x%08x] Length:%ld\n", sockFd, pEvUser, len);

			ret = _E_SUCC;
		}else if((errCode == S_SOCKET_ERROR) && 
				((errCode = WSAGetLastError()) == WSAEWOULDBLOCK)){
			ret = _E_SUCC;
		}
		
		if(ret != _E_SUCC){
			/* Fail Check */
			SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, 
				"Sock[%-8d][0x%08x] Error\n", sockFd, pEvUser);

			pCb = pEvUser->pCb;
			if(pCb && (pCb->cbErr)){
				return pCb->cbErr(pEvUser, errCode);
			}
		}
	}
	
	return ret;
}


static 	sInt32 	SockRx_Tcp(_t_sockEvUser * pEvUser, _t_sgbuf * pSgBuf, long sgCnt)
{
	long 			flag, len;
	int 			ret, errCode;
	S_SOCKET		sockFd;
	_t_sockEvCb *	pCb;

	ret 	= _E_FAIL;
	errCode = S_SOCKET_ERROR;
	
	if(	(pEvUser)  && ((sockFd =pEvUser->fd) != S_SOCKET_INVALID) && 
		(pSgBuf) && (sgCnt > 0)){
			/* OP */
			flag = 0;
			errCode = WSARecv(sockFd, 
							(LPWSABUF)(pSgBuf), sgCnt,
							&len, 	&flag, 
							NULL, NULL);	

		/* Check Ret */
		if(errCode == 0){
			SYS_TRACE(_gTraceLvl_Sock, TRACELVL_DEBUG, 
				"Sock[%-8d][0x%08x] Length:%ld\n", sockFd, pEvUser, len);
			
			ret = len;
		}else if((errCode == S_SOCKET_ERROR) && 
				((errCode = WSAGetLastError()) == WSAEWOULDBLOCK)){
			ret = -1;
		}
		
		if(ret != _E_SUCC){
			/* Fail Check */
			SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, 
				"Sock[%-8d][0x%08x] Error\n", sockFd, pEvUser);

			pCb = pEvUser->pCb;
			if(pCb && (pCb->cbErr)){
				return pCb->cbErr(pEvUser, errCode);
			}
		}
	}

	return ret;
}


static 	sInt32 	SockRx_Udp(_t_sockEvUser * pEvUser, _t_sgbuf * pSgBuf, long sgCnt, S_SOCKET_ADDRIN * peer)
{
	long 			flag, len;
	int 			ret, errCode, sLen;
	S_SOCKET		sockFd;
	_t_sockEvCb *	pCb;

	ret 	= _E_FAIL;
	errCode = S_SOCKET_ERROR;
	
	if(	(pEvUser)  && ((sockFd =pEvUser->fd) !=S_SOCKET_INVALID) && 
		(pSgBuf) && (sgCnt > 0) && peer ){
		/* OP */
		flag = 0; sLen = (sInt32)sizeof(S_SOCKET_ADDRIN);
		errCode = WSARecvFrom(sockFd, 
							(LPWSABUF)(pSgBuf), sgCnt,
							&len, &flag, 
							(S_SOCKET_ADDR *)peer, 
							&sLen,
							NULL, NULL);	

		/* Check Ret */
		if(errCode == 0){
			SYS_TRACE(_gTraceLvl_Sock, TRACELVL_DEBUG, 
				"Sock[%-8d][0x%08x] Length:%ld\n", sockFd, pEvUser, len);
			
			ret = len;
		}else if((errCode == S_SOCKET_ERROR) && 
				((errCode = WSAGetLastError()) == WSAEWOULDBLOCK)){
			ret = -1;
		}
		
		if(ret != _E_SUCC){
			/* Fail Check */
			SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, 
				"Sock[%-8d][0x%08x] Error\n", sockFd, pEvUser);

			pCb = pEvUser->pCb;
			if(pCb && (pCb->cbErr)){
				return pCb->cbErr(pEvUser, errCode);
			}
		}
	}

	return ret;
}


static 	S_SOCKET 	SockAccept_Tcp(_t_sockEvUser * pEvUser, S_SOCKET_ADDRIN * peer)
{
	int 			errCode, sLen;
	S_SOCKET 		sockAccept;
	S_SOCKET		sockFd;
	
	sockAccept 	= S_SOCKET_INVALID;
	if(	(pEvUser)  && ((sockFd =pEvUser->fd) != S_SOCKET_INVALID) ){
		sockAccept 	= S_SOCKET_INVALID;

		/* OP */
		sLen = (sInt32)sizeof(S_SOCKET_ADDRIN);
		sockAccept = WSAAccept(sockFd, (S_SOCKET_ADDR *)peer, &sLen, NULL, 0);
			
		/* Check Ret */
		if(sockAccept != S_SOCKET_INVALID ){
			SYS_TRACE(_gTraceLvl_Sock, TRACELVL_DEBUG, "Sock[%-8d]\n", sockAccept);
			/* Change FdState/LinkState, QueOP, Event Handle! */

		}else if((sockAccept == S_SOCKET_INVALID) && 
				((errCode = WSAGetLastError()) == WSAEWOULDBLOCK)){
			SYS_TRACE(_gTraceLvl_Sock, TRACELVL_DEBUG, "Accept Block\n");
		}
	}

	return sockAccept;
}



static 	sInt32 	SockConnect_Tcp(_t_sockEvUser * pEvUser, S_SOCKET_ADDRIN * peer)
{
	int 			ret, errCode;
	S_SOCKET		sockFd;
	
	ret 	= _E_FAIL;
	errCode = S_SOCKET_ERROR;

	if(	(pEvUser)  && ((sockFd =pEvUser->fd) != S_SOCKET_INVALID) ){
		/* OP */
		errCode = WSAConnect(sockFd, 	
						(S_SOCKET_ADDR*)peer, 
						sizeof(S_SOCKET_ADDRIN),
			  			NULL, NULL, NULL, NULL);
			
		/* Check Ret */
		if(errCode == 0){
			SYS_TRACE(_gTraceLvl_Sock, TRACELVL_DEBUG, 
				"Sock[%-8d]\n", sockFd);
			
			ret = _E_SUCC;
		}else if((errCode == S_SOCKET_ERROR) && 
				((errCode = WSAGetLastError()) == WSAEWOULDBLOCK)){
			ret = _E_FAIL;
		}
	}

	return ret;
}

/* --------------------------------------------------------
** Listen : WSAEventSelect
*/  
#if 0
sInt32 	SockListen_Tcp(_t_sockEvUser * pEvUser)
{
	/* Event Select Structure */
	int 			ret;
	S_SOCKET		sockFd;

	ret = _E_FAIL;
	if(	(pEvUser)  && ((sockFd = pEvUser->fd) != S_SOCKET_INVALID) ){
		ret = listen(sockFd, S_SOCKET_SOMAXCONN);
	}
	return ret;
}
#endif

/* --------------------------------------------------------
** WSAEventSelect
 */  
sInt32 	SockEvent_CR(_t_sockEvUser * pEvUser, WSANETWORKEVENTS * pEvents)
{
	sInt32 	i, errCode, mask, op;
	_t_sockEvCb * pCb;
	int 	(*	callback)();
	
	if(pEvUser && pEvents->lNetworkEvents){
		pCb = pEvUser->pCb;
		for(i=0, mask = 0X01; i<FD_MAX_EVENTS; i++, mask<<=1){
			callback = (pCb->cbDisp);
			if(pEvents->lNetworkEvents & mask){
				errCode = pEvents->iErrorCode[i];
				switch(i){
					case FD_READ_BIT:
					case FD_ACCEPT_BIT:
						op = S_EVOP_RX;
						break;

					case FD_WRITE_BIT:
					case FD_CONNECT_BIT:
						op = S_EVOP_TX;
						break;

					case FD_CLOSE_BIT:
					case FD_OOB_BIT:
					case FD_QOS_BIT:
					case FD_GROUP_QOS_BIT:
					case FD_ROUTING_INTERFACE_CHANGE_BIT:
					case FD_ADDRESS_LIST_CHANGE_BIT:
					default:
						op = S_EVOP_ERR;
						break;
				}

				if(callback){
					/* How to do with the ErrCode ? */
					callback(pEvUser, op, i);
				}
				
			}
		}
	}

	return _E_FAIL;
}


void 	EvSel_Init(_t_sysEvSel * pEvSel)
{
	int i;

	for(i=0; i<S_EVSEL_MAX; i++){
		pEvSel->event[i] 	= WSA_INVALID_EVENT;
		pEvSel->eUser[i] 	= NULL;
	}
	pEvSel->event[0] = WSACreateEvent();
	pEvSel->count = 1;
	pEvSel->flag  = 1;
	SYS_INIT_CS(&(pEvSel->lock));

	return;
}

void * 		EvSel_Exec(_t_sysEvSel * pEvSel)
{
	unsigned long ret, index;
	int 		  errCode;
	
	_t_sockEvUser 	* 	pEvUser;
	S_SOCKET 			sockFd;
	WSANETWORKEVENTS 	sockEv;

	_t_sysEvSel 		evSel;
	
	while(1){
#if 1
		/* Judge Dirty */
		if(pEvSel->flag == 1){
			SYS_ENTER_CS(&(pEvSel->lock));
			
			SYS_MEMCPY(&evSel, pEvSel, sizeof(_t_sysEvSel));
			pEvSel->flag = 0;
			
			SYS_LEAVE_CS(&(pEvSel->lock));
		}
#endif

		ret = WSAWaitForMultipleEvents(evSel.count, evSel.event, FALSE, S_EVSEL_TO, FALSE);
		switch(ret){
			case WSA_WAIT_TIMEOUT:
				break;

			case WAIT_IO_COMPLETION:
				break;

			case WSA_WAIT_FAILED:
				errCode = WSAGetLastError();
#if 0
				SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, "Sock EventSelect Fail %d\n", errCode);
#endif
				break;

			default:
				index = ret - WSA_WAIT_EVENT_0;
				pEvUser = evSel.eUser[index];

				/* Hack to Judge the EvUser's Index Set ! */
				if(	pEvUser && 
					(pEvUser->index != 0) &&
					((sockFd = pEvUser->fd) != S_SOCKET_INVALID)){
					ret = WSAEnumNetworkEvents(sockFd, pEvUser->event, &sockEv);
					if(ret == 0){
						SockEvent_CR(pEvUser, &sockEv);
					}else{
						errCode = WSAGetLastError();
						SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, "Sock[%d] EventEnum %d\n", 
							sockFd, errCode);
					}
				}
				break;
		}
	}

	return NULL;
}



#if 0
WSACreateEvent
CreateEvent(NULL, FALSE, FALSE, NULL) 
WSACloseEvent
CloseHandle
#endif
static 	__inline sInt32 	_SockEv_Init(_t_sockEvUser * pEvUser)
{
	sInt32 ret;

	ret = _E_FAIL;
	if(pEvUser){
		if((pEvUser->event= WSACreateEvent())!= WSA_INVALID_EVENT){
			#if 1
			WSAEventSelect( pEvUser->fd, pEvUser->event,
						FD_READ		|	FD_WRITE 	|
						FD_ACCEPT 	| 	FD_CONNECT 	|
						FD_CLOSE);
			#endif
			pEvUser->index = 0;	/* Init */
			ret = _E_SUCC;
		}
	}
	return ret;
}


static 	__inline sInt32 	_SockEv_Fini(_t_sockEvUser * pEvUser)
{
	sInt32 ret;

	ret = _E_FAIL;
	if(pEvUser){
		if(WSACloseEvent(pEvUser->event)== TRUE){
			ret = _E_SUCC;
		}
		pEvUser->index = 0; /* Fini*/
	}
	return ret;
		
}

sInt32 	EvSel_Add(_t_sysEvSel * pEvSel, _t_sockEvUser * pEvUser)
{
	int ret, count;

	ret = _E_FAIL;

	if(pEvSel && pEvUser){
		if(_SockEv_Init(pEvUser) == _E_SUCC){
			SYS_ENTER_CS(&(pEvSel->lock));
			/* Set Dirty */
			pEvSel->flag  = 1;
			#if 0
			SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, "EvAdd :%p -> %d\n", pEvUser, pEvSel->count);
			#endif
			count = pEvSel->count;
			if(count < S_EVSEL_MAX){
				pEvUser->index 			= count;		/* Set Index */
				pEvSel->eUser[count] 	= pEvUser;
				pEvSel->event[count] 	= pEvUser->event;
				pEvSel->count += 1;
				ret = _E_SUCC;
			}
			else{
				_SockEv_Fini(pEvUser);
				SYS_TRACE(_gTraceLvl_Sock, TRACELVL_DEBUG, "Sock EvSel Add Fail %d\n", pEvUser->fd);
			}
			SYS_LEAVE_CS(&(pEvSel->lock));
		}
	}

	return ret;
}


sInt32 	EvSel_Del(_t_sysEvSel * pEvSel, _t_sockEvUser * pEvUser)
{
	int 	ret, i, count;
	_t_sockEvUser 	** ppUser;
	WSAEVENT		*  pEvent;
	ret = _E_FAIL;
	
	if(pEvSel && pEvUser ){
		SYS_ENTER_CS(&(pEvSel->lock));
		/* Set Dirty */
		pEvSel->flag  = 1;
		
		i = pEvUser->index;
		#if 0
		SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, "EvDel :%p ->%d %d\n", pEvUser, i, pEvSel->count);
		#endif
		count  = pEvSel->count;
		pEvent = (pEvSel->event);
		ppUser = (pEvSel->eUser);
		for(; i<(count-1); i++){
			pEvent[i] = pEvent[i + 1];
			ppUser[i] = ppUser[i + 1];
			ppUser[i]->index = i;
		}
		
		pEvSel->count -= 1;

		_SockEv_Fini(pEvUser);
		SYS_LEAVE_CS(&(pEvSel->lock));


		ret = _E_SUCC;
	}

	return ret;
}


sInt32 	EvSel_Mod(_t_sysEvSel * pEvSel, _t_sockEvUser * pEvUser)
{
	int 	ret;
	ret = _E_FAIL;
	
	if(pEvSel && pEvUser ){
		SYS_ENTER_CS(&(pEvSel->lock));
		WSAEventSelect( pEvUser->fd, pEvUser->event,
					FD_READ		| 	FD_CLOSE);
		SYS_LEAVE_CS(&(pEvSel->lock));

		ret = _E_SUCC;
	}

	return ret;
}


/* --------------------------------------------------------
** Lib Function
*/  
sInt32		SockLib_Init(void)
{
	WSADATA		WSAData = { 0 };
	if ( 0 != WSAStartup( WSA_VERSION, &WSAData ) ){
		return _E_FAIL;
	}
	return _E_SUCC;
}

void		SockLib_Fini(void)
{
	WSACleanup();
}



